package main

import (
	"net/url"
	"path/filepath"
	//"net/url"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"

	"github.com/Unknwon/goconfig"
	"github.com/astaxie/beego/logs"
	"github.com/go-errors/errors"
)

var (
	Log     *logs.BeeLogger
	worms   []string
	usrs    map[string]string
	version = "3.10.0"
)

const (
	NUM = 12
	GAP = 60
)

func init() {
	var err error
	file, _ := exec.LookPath(os.Args[0])
	path := filepath.Dir(file)
	c, err := goconfig.LoadConfigFile(filepath.Join(path, "app.conf"))
	if err != nil {
		Log.Error(err.Error())
		return
	}
	usrs, err = c.GetSection("users")
	if err != nil {
		Log.Error(err.Error())
		return
	}
	worms = c.MustValueArray("worms", "names", ",")

	Log = logs.NewLogger(10000)
	Log.SetLogFuncCallDepth(3)
	Log.EnableFuncCallDepth(true)
	//os.MkdirAll("c:/logs/uc", os.ModeDir)
	Log.SetLogger("console", "")
	Log.SetLogger("file", `{"filename":"`+"c:/gold.log"+`","daily":true}`)
	Log.SetLogger("smtp", `{"level":3,"subject":"gold","fromAddress":"songkemail@163.com","username":"songkemail@163.com","password":"songke198916","host":"smtp.163.com:25","sendTos":["553403792@qq.com"]}`)
}

func checkNewVersion(phone string) (ver string) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
			ver = version
		}
	}()
	url := "https://api.huangjinqianbao.com/server/info/detectionUpdated"
	payload := strings.NewReader(fmt.Sprintf("telephone=%s", phone))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("x-requested-with", "XMLHttpRequest")
	req.Header.Add("cache-control", "no-cache")
	req.Header.Add("version", version)
	req.Header.Add("deviceId", "EDC9CD07E49943904229E9CC54549005")
	req.Header.Add("channel", "gbanker_wap")
	req.Header.Add("platform", "Phone")
	req.Header.Add("scene", "Android")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return version
	}
	Log.Debug("body:%v", string(body))
	if v, ok := rst["data"]; ok {
		Log.Debug("data:%v", v)
		if vv, okv := v.(map[string]interface{})["newVersionCode"]; okv {
			if vv.(string) != "" {
				return vv.(string)
			}
		}
	}

	return version
}

func dig(phone, sid string) (err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://activity.g-banker.com/digGold/dig"
	payload := strings.NewReader(fmt.Sprintf("telephone=%s&sessionId=%s", phone, sid))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("x-requested-with", "XMLHttpRequest")
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	Log.Info(string(body))

	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return errors.New(err)
	}
	if v, ok := rst["digResultType"]; ok {
		if int(v.(float64)) == 0 {
			Log.Info("%s dig none, can continue diging", phone)
		}
	}

	return nil

}

func helpdig(usr, userCode, wxOpenId, wxnickName string) (enough bool, err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://activity.g-banker.com/weChatDigGold/helpDigGold"

	buffer := new(bytes.Buffer)
	fmt.Fprintf(buffer, "userCode=%s&timestamp=%d&wxOpenId=%s&wxNickName=%s&wxHeadImgUrl=%22%22", userCode, int64(time.Now().Unix()*1000), wxOpenId, wxnickName)

	req, _ := http.NewRequest("POST", url, buffer)

	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return true, errors.New(err)
	}
	Log.Info("%v", string(body))
	if v, ok := rst["helpedDigData"]; ok {
		diginfo := v.(map[string]interface{})
		if diginfo["awardGoldWeight"] == nil {
			return false, nil
		}
		weight := diginfo["awardGoldWeight"].(float64)
		Log.Info("help %s dig weight %d", usr, int(weight))
		return weight >= NUM, nil
	}
	return true, nil
}

//func helpdig_until_enough(userCode, wxOpenId, wxnickName string) {
//	t := time.AfterFunc(time.Minute, func() { helpdig_until_enough(userCode, wxOpenId, wxnickName) })
//	t.Stop()
//}

var wg sync.WaitGroup

func main() {
	//	defer func() {
	//		if ex := recover(); ex != nil {
	//			Log.Error("%v", ex)
	//		}
	//	}()
	version = checkNewVersion("18530850471")
	Log.Debug("version:%v", version)

	isdig := flag.Bool("d", true, "help dig gold")
	isexchange := flag.Bool("e", false, "exchange gold")
	flag.Parse()

	for usr, pwd := range usrs {

		wg.Add(1)

		go func(usr, pwd string) {
			defer func() {
				wg.Done()
			}()
			deviceid := string(Krand(15, KC_RAND_KIND_NUM))
			sid, err := login(usr, pwd, deviceid)
			if err != nil {
				Log.Error(err.Error())
				return
			}
			// exchange
			if *isexchange {
				Log.Info("%s dig gold", usr)
				dig(usr, sid)
				Log.Info("%s exhcange gold", usr)
				getGifts(usr, sid, deviceid)
			}
			// help dig
			if *isdig {
				Log.Info("help %s dig gold", usr)

				userCode, err := share(usr)
				if err != nil {
					Log.Error(err.Error())
					return
				}
				//				getWapShareInfo(deviceid, sid, usr)
				//				Log.Debug("usrcode:%v", userCode)
				if err := shareInSuccess(deviceid, sid, usr); err != nil {
					Log.Error("shareinsuccess err:%v", err.Error())
					return
				}
				if userCode != "" {
					for {
						b, err := helpdig(usr, userCode, wxOpenId(), wxnickName())
						if err != nil {
							Log.Error(err.Error())
						}
						if b {
							break
						}
						time.Sleep(time.Second * GAP)
					}
				}

			}
		}(usr, pwd)

		time.Sleep(time.Second * 5)
	}

	wg.Wait()
	Log.Info("exit")
}

func wxOpenId() string {
	seed := rand.Intn(8)
	return "o" + string(Krand(seed+25, KC_RAND_KIND_ALL))
}

func share(phone string) (userCode string, err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://activity.g-banker.com/info/getShareInfo"

	buffer := new(bytes.Buffer)
	fmt.Fprintf(buffer, "telephone=%s&code=goldMiner", phone)

	req, _ := http.NewRequest("POST", url, buffer)

	req.Header.Add("content-type", "application/x-www-form-urlencoded")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return "", errors.New(err)
	}
	if v, ok := rst["url"]; ok {
		shareinfo := v.(string)
		begin := strings.Index(shareinfo, "=")
		end := strings.Index(shareinfo, "&timestamp=")
		userCode = shareinfo[begin+1 : end]
		return userCode, nil
	}
	return "", errors.New("share bad response:" + string(body))

}

func shareInSuccess(deviceid, sid, phone string) (err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://api.huangjinqianbao.com/user/share/shareInSuccess"

	reqbody, _ := json.Marshal(map[string]interface{}{"shareToPlatform": "1", "telephone": phone, "code": "goldMiner"})
	payload := strings.NewReader(string(reqbody))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("version", version)
	req.Header.Add("deviceId", deviceid)
	req.Header.Add("channel", "gbanker_wap")
	req.Header.Add("platform", "Phone")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("scene", "Android")
	req.Header.Add("sessionId", sid)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return errors.New(err)
	}
	if v, ok := rst["code"]; ok {
		code := v.(string)
		if code != "0000" {
			return errors.New("shareInSuccess bad response:" + string(body))
		}
	}
	return nil

}

func getWapShareInfo(deviceid, sid, phone string) (err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://api.huangjinqianbao.com/user/share/getWapShareInfo"

	reqbody, _ := json.Marshal(map[string]interface{}{"telephone": phone, "code": "goldMiner"})
	payload := strings.NewReader(string(reqbody))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("version", version)
	req.Header.Add("deviceId", deviceid)
	req.Header.Add("channel", "gbanker_wap")
	req.Header.Add("platform", "Phone")
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("scene", "Android")
	req.Header.Add("sessionId", sid)

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return errors.New(err)
	}
	Log.Debug("getWapShareInfo:%v", string(body))
	//	if v, ok := rst["code"]; ok {
	//		code := v.(string)
	//		if code != "0000" {
	//			return errors.New("shareInSuccess bad response:" + string(body))
	//		}
	//	}
	return nil

}

/*
func query() {

	url := "https://api.huangjinqianbao.com/server/price/query"

	payload := strings.NewReader("{\"telephone\":\"18502566016\",\"queryFlag\":\"3\"}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("telephone", "13303891285")
	req.Header.Add("version", version)
	req.Header.Add("deviceid", "354778061920629")
	req.Header.Add("channel", "gbanker_web")
	req.Header.Add("platform", "Phone")
	req.Header.Add("content-type", "application/json")
	req.Header.Add("scene", "Android")
	req.Header.Add("sessionid", "ed391a9251f148ee85f1672127fab0fc")
	req.Header.Add("cache-control", "no-cache")
	req.Header.Add("postman-token", "bb6bf6cb-31e6-abc4-0117-6595a02237a5")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}*/

func exchange(giftCode, phone, sid, deviceid string) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://api.huangjinqianbao.com/server/gift/updateGiftExchange"

	reqbody, _ := json.Marshal(map[string]interface{}{"giftCode": giftCode, "telephone": phone})
	payload := strings.NewReader(string(reqbody))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("version", version)
	req.Header.Add("deviceid", deviceid)
	req.Header.Add("channel", "gbanker_web")
	req.Header.Add("platform", "Phone")
	req.Header.Add("content-type", "application/json")
	req.Header.Add("scene", "Android")
	req.Header.Add("sessionid", sid)
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	Log.Info("%s exchange result:%s", phone, string(body))
}

func getGifts(phone, sid, deviceid string) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://api.huangjinqianbao.com/server/gift/getUserGiftDetails"
	reqbody, _ := json.Marshal(map[string]interface{}{"type": "1", "start": "0", "telephone": phone, "size": "15"})
	payload := strings.NewReader(string(reqbody))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("x-requested-with", "XMLHttpRequest")
	req.Header.Add("version", version)
	req.Header.Add("deviceid", deviceid)
	req.Header.Add("channel", "gbanker_web")
	req.Header.Add("platform", "Phone")
	req.Header.Add("content-type", "application/json")
	req.Header.Add("scene", "Android")
	req.Header.Add("sessionid", sid)
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	type Rst struct {
		Data struct {
			Gifts []struct {
				GiftExpireDate string `json:"giftExpireDate"`
				GiftSource     string `json:"giftSource"`
				GiftType       int    `json:"giftType"`
				GoldWeight     int    `json:"goldWeight"`
				GiftCode       string `json:"giftCode"`
			} `json:"userGiftDatas"`
		} `json:"data"`
		ServerTime int64  `json:"serverTime"`
		Code       string `json:"code"`
		Msg        string `json:"msg"`
	}

	var rst Rst
	if err := json.Unmarshal(body, &rst); err != nil {
		fmt.Println(err)
		return
	}
	if rst.Code == "0000" && len(rst.Data.Gifts) > 0 {
		for _, gift := range rst.Data.Gifts {
			exchange(gift.GiftCode, phone, sid, deviceid)
		}
	}
}

func login(usr, pwd, deviceid string) (sid string, err error) {
	defer func() {
		if err := recover(); err != nil {
			Log.Error("%v", err)
		}
	}()
	url := "https://api.huangjinqianbao.com/user/base/login"

	reqbody, _ := json.Marshal(map[string]interface{}{"password": pwd, "telephone": usr})
	payload := strings.NewReader(string(reqbody))

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/POST; charset=utf-8")
	req.Header.Add("version", version)
	req.Header.Add("channel", "gbanker_web")
	req.Header.Add("deviceid", deviceid)
	req.Header.Add("useragent", "Mozilla/5.0 (Linux; Android 4.4.4; SM-G8508S Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/33.0.0.0 Mobile Safari/537.36")
	req.Header.Add("platform", "Phone")
	req.Header.Add("scene", "Android")
	req.Header.Add("cache-control", "no-cache")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	var rst map[string]interface{}
	if err := json.Unmarshal(body, &rst); err != nil {
		return "", errors.New(err)
	}
	if v, ok := rst["data"]; ok {
		session := v.(map[string]interface{})
		if v1, ok1 := session["sessionid"]; ok1 {
			sid := v1.(string)
			return sid, nil
		}
	}
	return "", errors.New("login bad response:" + string(body))
}

func wxnickName() string {
	idx := rand.Intn(len(worms))
	l, _ := url.Parse(worms[idx])
	return l.String()
}
